<?php
namespace app\common\controller;

class Wxpay2 {


    protected $appid;
    protected $mch_id;
    protected $sub_mch_id;
    protected $sub_appid;
    protected $key;
    protected $openid;
    protected $out_trade_no;
    protected $body;
    protected $total_fee;
    protected $root;
    function __construct($appid, $openid, $mch_id, $key,$out_trade_no,$body,$total_fee,$root,$sub_appid,$sub_mch_id) {
        $this->appid = $appid;//服务商的
        $this->openid = $openid;
        $this->mch_id = $mch_id;//服务商的
        $this->sub_mch_id = $sub_mch_id;
        $this->sub_appid = $sub_appid;
        $this->key =  $key;//服务商的
        $this->out_trade_no = $out_trade_no;
        $this->body = $body;
        $this->total_fee = $total_fee;
        $this->root = $root;
    }


    public function pay() {
        //统一下单接口
        $return = $this->unifiedorder();
        return $return;
    }

    //统一下单接口(服务商支付)
    private function unifiedorder() {
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
        $create_noncestr =  $this->create_noncestr(32);

        $parameters = array(
            'appid' => $this->appid,
            'mch_id' => $this->mch_id,
            'sub_mch_id'=>$this->sub_mch_id,
            'nonce_str' => $create_noncestr,
            'body'=>'餐饮小程序',
            'out_trade_no'=>$this->out_trade_no,
            'total_fee'=>$this->total_fee,
            'notify_url'=>$this->root,
            'trade_type'=>'JSAPI',
            'openid'=>$this->openid,
            'spbill_create_ip' => strval($_SERVER['SERVER_ADDR']),//服务器IP
        );

        $parameters['sign'] = $this->getSign($parameters, $this->key);//getSign函数见图2,C('KEY'):商户支付密钥

        $xml = $this->arrayToXml($parameters);

        $result = $this->http_request($url,$xml); //dump($result);die;

        $postObj   = simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        $jsonStr   = json_encode($postObj);
        $jsonArray = json_decode($jsonStr,true);

        $prepayId  = $jsonArray['prepay_id'];


        $option 				= 	array();
        $option["appId"] 		= 	$this->appid;
        $option["timeStamp"] 	= 	(string)time();
        $option["nonceStr"] 	= 	$create_noncestr;
        $option["package"] 		= 	"prepay_id={$prepayId}";
        $option["signType"] 	= 	"MD5";

        $option["paySign"] 		= 	$this->getPaySign_isv($option, 'MD5');

        return $option;

    }



    //4、随机字符串
    public function create_noncestr($length=16){
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $str = '';
        for($i=0; $i<$length; $i++){
            $str.=substr($chars, mt_rand(0, strlen($chars)-1), 1);
        }
        return $str;
    }


    //5、生成签名
    public function getSign($Obj,$key){
        foreach($Obj as $k =>&$v){
            $Parameters[$k] = $v;
        }
        //签名步骤一，按字典序排序参数
        ksort($Parameters);


        $String = $this->formaBizQueryParaMap($Parameters,false);


        //签名步骤二：在string后加入Key
        $String = $String . "&key=" . $key;
        //echo "[string2]".$String."<br>";

        //签名步骤三 ： MD5加密
        $String = md5($String);
        //echo "[string3]".$String."<br>";

        //签名步骤四，所有字符转为大写
        $result_ = strtoupper($String);
        //echo "[result]".$String."<br>";

        return $result_;

    }


    /**
     * 6、转xml
     */
    protected function arrayToXml($array, $level = 1)
    {
        $result = $level == 1 ? "<xml>" : '';
        foreach($array as $key => $value) {
            if (is_numeric($key)) {
                $key = $value['TagName'];
                unset($value['TagName']);
            }
            if(!is_array($value)) {
                $result .= "<" . $key . ">" . (is_numeric($value) ? '<![CDATA[' : '') . $value . (is_numeric($value) ? ']]>' : '') . "</" . $key . ">";
            } else {
                $result .=  "<" . $key . ">" . $this->arrayToXml($value,$level + 1) . "</" . $key . ">";
            }
        }
        $result = preg_replace("/([\x01-\x08\x0b-\x0c\x0e-\x1f])+/", '', $result);
        return $level == 1 ? $result . "</xml>" : $result;
    }


    //7、作用，以post方式提交xml到对应的借口url
    private function postXmlCurl($xml,$url,$useCert = false,$second=30){
        $ch = curl_init();
        //设置超时
        curl_setopt($ch,CURLOPT_TIMEOUT,$second);
        //如果有配置代理这里设置代理
        /*if($this->wxpay_config['CURL_PROXY_HOST']!="0.0.0.0" && $this->wxpay_config['CURL_PROXY_PORT']!=0){
            curl_setopt($ch,CURLOPT_PROXY,$this->wxpay_config['CURL_PROXY_HOST']);
            curl_setopt($ch,CURLOPT_PROXYPORT,$this->wxpay_config['CURL_PROXY_PORT']);
        }*/
        curl_setopt($ch,CURLOPT_URL,$url);
        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2); //严格教研
        //设置header
        curl_setopt($ch,CURLOPT_HEADER,FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
        if($useCert == true){
            //设置证书
            //使用证书
            curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
            curl_setopt($ch,CURLOPT_SSLCERT,dirname(__FILE__).'/apiclient_cert.pem');	     //证书
            curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
            curl_setopt($ch,CURLOPT_SSLKEY,dirname(__FILE__).'/apiclient_key.pem') ;		 //证书
        }
        //post提交方式
        curl_setopt($ch,CURLOPT_POST,TRUE);
        curl_setopt($ch,CURLOPT_POSTFIELDS,$xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果
        if($data){
            curl_close($ch);
            return $data;
        }else{
            $error = curl_errno($ch);
            curl_close($ch);
            //$this->error('curl出错',$error,'wxpostXmlCurl');
            return $error;
        }
    }

    //8、xml 转为array
    public function xmlToArray($xml){
        //将XML转为array
        $array_data = json_decode(json_encode(simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOCDATA)),TRUE)	;
    }

    //9、作用，格式化参数，签名过程中需要使用
    public function formaBizQueryParaMap($paraMap,$urlencode){
        $buff = "";
        ksort($paraMap);
        foreach($paraMap as $k =>&$v){
            if($urlencode){
                $v = urlencode($v);
            }
            $buff .= $k . "=" . $v . "&";
        }
        $reqPar = '';
        if(strlen($buff)>0){
            $reqPar = substr($buff,0,strlen($buff)-1);
        }
        return $reqPar;

    }

    /*9、 POST服务器接口请求*/
    function http_request($url, $data = null){
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if(!empty($data)){
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }



    /*9、 继续验签名 */
    public function getPaySign_isv(array $data, $signType = 'MD5', $buff = '')
    {
        unset($data['sign']);
        ksort($data);
        foreach ($data as $k => $v) {
            $buff .= "{$k}={$v}&";
        }
        $buff .= ("key=" .  $this->key);
        if (strtoupper($signType) === 'MD5') {
            return strtoupper(md5($buff));
        }
        return strtoupper(hash_hmac('SHA256', $buff, $this->key));
    }

}		
			
		
